package com.cml.client.infrastructure;

import com.cml.client.common.context.ApplicationContext;
import com.cml.client.domain.entity.Server;
import com.cml.client.domain.service.ServerHAService;
import com.cml.common.dto.entity.Message;
import com.cml.common.serializable.MessageSerializable;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * 姓名：陈茂林
 * 时间：2023/10/16 14:38
 * 描述：
 */
public class NetworkManager {
    private Logger logger = Logger.getLogger(NetworkManager.class);

    private static Map<String,Server> serverConnContaion = new HashMap<>();

    private static final Long SELECTOR_TIMEOUT = 5000L;

    private Selector selector;

    private ApplicationContext applicationContext;

    public NetworkManager(ApplicationContext applicationContext){
        this.applicationContext=applicationContext;
        try {
            this.selector = Selector.open();
            ServerIOThread serverIOThread = new ServerIOThread(selector);
            serverIOThread.start();
        }catch (Exception e){
            logger.error("创建网络连接错误！");
            throw new RuntimeException(e);
        }
    }



    public void connServiceServer(Server server) throws Exception {
        Server serverConn = serverConnContaion.get(server.getServerConnDesc());
        if(serverConn == null){
            SocketChannel  socket = SocketChannel.open();
            socket.configureBlocking(false);
            socket.socket().setSoLinger(false, -1);
            socket.socket().setTcpNoDelay(true);
            //注册连接事件
            socket.register(selector, SelectionKey.OP_CONNECT);
            //发起连接
            socket.connect(new InetSocketAddress(server.getIp() , server.getPort()));
            while (serverConnContaion.get(server.getServerConnDesc()) == null){
                logger.debug("等待连接完成！！！");
            }
            MessageQueueManager.createQueue(server.getServerConnDesc());
        }
    }


    class  ServerIOThread extends  Thread{

        private Selector selector;
        public ServerIOThread(Selector selector ){
            this.selector=selector;
        }

        @Override
        public void run() {
            while (true){

                try {
                    //在注册的键中选择已准备就绪的事件
                    selector.select(SELECTOR_TIMEOUT);
                //已选择键集
                    Set<SelectionKey> keys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = keys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        try {
                            //删除当前键，避免重复消费
                            iterator.remove();
                            if (key.isConnectable()) {
                                //在非阻塞模式下connect也是非阻塞的，所以要确保连接已经建立完成
                                while (!socketChannel.finishConnect()) {
                                    logger.info("连接中");
                                }
                                SelectionKey serverKey =key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
                                Server serverConn = Server.Builder.build(socketChannel);
                                serverConnContaion.put(serverConn.getServerConnDesc(),serverConn);

                                serverKey.attach(serverConn);
                            }
                            //处理输入事件
                            if (key.isReadable()) {
                                Server server = (Server) key.attachment();
                                Message message = MessageSerializable.decoder(socketChannel);
                                if(message != null){
                                    MessageQueueManager.sendResponseMessage(message);
                                }

                            }else if (key.isWritable()) {
                                Server server = (Server) key.attachment();
                                Message message =MessageQueueManager.peekRequestMessage(server.getServerConnDesc());
                                if (message == null){
                                    continue;
                                }
                                //发送消息给服务端
                                socketChannel.write(MessageSerializable.encoder(message));
                                if(!message.getMessageBuffer().hasRemaining()){
                                    MessageQueueManager.pollRequestMessage(server.getServerConnDesc());
                                }
                            }
                        }catch (Exception e){
                            logger.error(e);
                            Server server = Server.Builder.build(socketChannel);
                            ServerHAService.getInstance(applicationContext).ha(server);
                            socketChannel.close();
                            throw new RuntimeException("服务端网络已断开");
                        }

                    }
                } catch (IOException e) {
                    logger.error(e);
                    throw new RuntimeException(e);
                }

            }
        }
    }

    public void clearResource(Server server) {
            NetworkManager.serverConnContaion.remove(server);
            MessageQueueManager.removeRequestQueue(server.getServerConnDesc());
    }

}
